import model.backoffice.{
  BackofficeParams,
  ItemAndInfo,
  JsonGeneralFields,
  JsonResponse,
  ResponseUserInfo
}
import model.postgresql.PgBaseEvent
import model.vk.UserInfo
import zio.ZIO
import zio.json.*
import zio.http.Response

object Responses {
  private case class CountAndFetchItems(count: Long, items: List[ItemAndInfo])

  private def toResponseUserInfo(userInfo: UserInfo): ResponseUserInfo =
    ResponseUserInfo(userInfo.first_name, userInfo.last_name)

  private def convertPair(items: List[(PgBaseEvent, UserInfo)]) = {
    items.map(pair => ItemAndInfo(pair._1, toResponseUserInfo(pair._2)))
  }

  private def getCountAndFetchData(path: String, validatedParams: BackofficeParams) = path match
    case "likes" =>
      for {
        items <- DBService.fetchLikesWithInfo(validatedParams)
        count <- DBService.countLikes(validatedParams)
      } yield CountAndFetchItems(count, convertPair(items))

    case "unlikes" =>
      for {
        items <- DBService.fetchUnlikesWithInfo(validatedParams)
        count <- DBService.countUnlikes(validatedParams)
      } yield CountAndFetchItems(count, convertPair(items))

    case "joins" =>
      for {
        count <- DBService.countJoins(validatedParams)
        items <- DBService.fetchJoinsWithInfo(validatedParams)
      } yield CountAndFetchItems(count, convertPair(items))

    case "leaves" =>
      for {
        count <- DBService.countLeaves(validatedParams)
        items <- DBService.fetchLeavesWithInfo(validatedParams)
      } yield CountAndFetchItems(count, convertPair(items))

    case "comments" =>
      for {
        count <- DBService.countComments(validatedParams)
        items <- DBService.fetchCommentsWithInfo(validatedParams)
      } yield CountAndFetchItems(count, convertPair(items))

    case "reposts" =>
      for {
        count <- DBService.countReposts(validatedParams)
        items <- DBService.fetchRepostsWithInfo(validatedParams)
      } yield CountAndFetchItems(count, convertPair(items))

    case x => throw Exception(s"Unknown event type: $x")

  def buildResponse(
      path: String,
      validatedParams: BackofficeParams
  ): ZIO[DBService.Service, Throwable, Response] =
    for {
      countAndData <- getCountAndFetchData(path, validatedParams).orDie
      response <- ZIO.succeed(
        Response.text(
          JsonResponse(
            items = countAndData.items,
            query = JsonGeneralFields(
              validatedParams.offset,
              validatedParams.limit,
              size = countAndData.items.size,
              countAndData.count.toInt
            )
          ).toJsonPretty
        )
      )
    } yield response
}
